﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection;

namespace IGolovkine.Core.Diagnostics
{
    public static class Debug
    {
        private const string DebugCondition = "DEBUG";

        public delegate T MemberReference<T>();

        [Conditional(DebugCondition)]
        public static void NotNullOrEmpty(Expression<MemberReference<string>> reference)
        {
            MemberReference<string> compiledReference = reference.Compile();
            string value = compiledReference();
            if (value == string.Empty || value == null)
            {
                MemberInfo member = GetMemberFromExpression(reference.Body);
                string message;
                if (value == string.Empty)
                {
                    message = string.Format("Parameter '{0}' has the value of string.Empty", member.Name, member);
                }
                else
                {
                    message = string.Format("Parameter '{0}' has the value of 'null'", member.Name, member);
                }
                throw new ArgumentOutOfRangeException(member.Name, value, message);
            }
        }

        [Conditional(DebugCondition)]
        public static void Expect(Expression<Func<bool>> condition)
        {
            Func<bool> compiledCondition = condition.Compile();
            if (compiledCondition() == false)
            {
                string conditionExpression = condition.ToString();
                string message = string.Format("{0} doesn't evaluate to True", condition);
                throw new ArgumentException(message);
            }
        }

        [Conditional(DebugCondition)]
        public static void NotDefault<T>(Expression<MemberReference<T>> reference)
        {

            MemberReference<T> compiledReference = reference.Compile();
            if (object.Equals(compiledReference(), default(T)))
            {
                MemberInfo member = GetMemberFromExpression(reference.Body);
                string message = string.Format("Parameter '{0}' has the default value of type '{1}'", member.Name, member);
                throw new ArgumentNullException(member.Name, message);
            }
        }

        private static MemberInfo GetMemberFromExpression(Expression memberReference)
        {
            MemberExpression memberExpression = memberReference as MemberExpression;
            if (memberExpression != null)
            {
                return memberExpression.Member;
            }
            else
            {
                throw new InvalidOperationException("Invalid expression used as a reference");
            }
        }
    }
}
